package com.jerry.chinesechess.util;

import com.jerry.chinesechess.enums.Player;
import com.jerry.chinesechess.model.Board;
import com.jerry.chinesechess.model.Piece;
import com.jerry.chinesechess.model.Position;

public class MoveValidator {
    private MoveValidator(){}
    public static boolean isValidMove(Board board, Position from, Position to) {
        Piece piece = board.getPieceAt(from);
        if (piece == null) return false;
        if (pieceBelongSamePlayer(board, from, to)) return false;
        if (from.equals(to)) return false;
        return switch (piece.getType()) {
            case GENERAL -> isValidGeneralMove(from, to, piece.getPlayer());
            case CHARIOT -> isValidChariotMove(board, from, to);
            case HORSE -> isValidHorseMove(board, from, to);
            case ELEPHANT -> isValidElephantMove(board, from, to, piece.getPlayer());
            case ADVISOR -> isValidAdvisorMove(from, to, piece.getPlayer());
            case CANNON -> isValidCannonMove(board, from, to);
            case SOLDIER -> isValidSoldierMove(from, to, piece.getPlayer());
            default -> false;
        };
    }
    
    private static boolean isValidGeneralMove(Position from, Position to, Player player) {
        // 将/帅只能在九宫格内移动
        int palaceMinRow = player == Player.RED ? 7 : 0;
        int palaceMaxRow = player == Player.RED ? 9 : 2;
        int palaceMinCol = 3;
        int palaceMaxCol = 5;
        
        if (to.getCol() < palaceMinCol || to.getCol() > palaceMaxCol || 
            to.getRow() < palaceMinRow || to.getRow() > palaceMaxRow) {
            return false;
        }
        
        // 只能走一步
        int rowDiff = Math.abs(to.getRow() - from.getRow());
        int colDiff = Math.abs(to.getCol() - from.getCol());
        
        return (rowDiff == 1 && colDiff == 0) || (rowDiff == 0 && colDiff == 1);
    }

    /**
     * 车移动规则
     * @param board 棋盘
     * @param from 起始点
     * @param to 目标点
     * @return 是否可移动
     */
    private static boolean isValidChariotMove(Board board, Position from, Position to) {
        if (from.getRow() != to.getRow() && from.getCol() != to.getCol()){
            return false;
        }
        Position fromCopy = new Position(from.getRow(), from.getCol());
        while (fromCopy.getRow() != to.getRow() || fromCopy.getCol() != to.getCol()){
            if (fromCopy.getRow() != to.getRow()){
                fromCopy.setRow(fromCopy.getRow() + (to.getRow() > fromCopy.getRow() ? 1 : -1));
            } else {
                fromCopy.setCol(from.getCol() + (to.getCol() > fromCopy.getCol() ? 1 : -1));
            }
            if (board.getPieceAt(from) != null){
                return false;
            }
        }

        return true;
    }

    private static boolean isValidHorseMove(Board board, Position from, Position to) {
        // 计算行和列的差值
        int rowDiff = Math.abs(to.getRow() - from.getRow());
        int colDiff = Math.abs(to.getCol() - from.getCol());

        // 判断是否符合“日”字形移动
        if (!((rowDiff == 2 && colDiff == 1) || (rowDiff == 1 && colDiff == 2))) {
            return false;
        }

        // 检查是否有“蹩马腿”
        if (rowDiff == 2) {
            int midRow = (to.getRow() + from.getRow()) / 2;
            return board.getPieceAt(new Position(midRow, from.getCol())) == null;
        } else {
            int midCol = (to.getCol() + from.getCol()) / 2;
            return board.getPieceAt(new Position(from.getRow(), midCol)) == null;
        }
    }

    private static boolean isValidElephantMove(Board board, Position from, Position to, Player player) {
        // Calculate row and column differences
        int rowDiff = Math.abs(to.getRow() - from.getRow());
        int colDiff = Math.abs(to.getCol() - from.getCol());

        // Check if the move is exactly two points diagonally
        if (rowDiff != 2 || colDiff != 2) {
            return false;
        }

        // Check if the Elephant is crossing the river
        int riverBoundary = player == Player.RED ? 5 : 4;
        if ((player == Player.RED && to.getRow() < riverBoundary) ||
                (player == Player.BLACK && to.getRow() > riverBoundary)) {
            return false;
        }

        // Check if the path is blocked (蹩象腿)
        int midRow = (from.getRow() + to.getRow()) / 2;
        int midCol = (from.getCol() + to.getCol()) / 2;
        return board.getPieceAt(new Position(midRow, midCol)) == null;
    }
    private static boolean isValidAdvisorMove(Position from, Position to, Player player) {
        // Calculate row and column differences
        int rowDiff = Math.abs(to.getRow() - from.getRow());
        int colDiff = Math.abs(to.getCol() - from.getCol());

        // Check if the move is exactly one point diagonally
        if (rowDiff != 1 || colDiff != 1) {
            return false;
        }

        // Define the palace boundaries
        int palaceMinRow = player == Player.RED ? 7 : 0;
        int palaceMaxRow = player == Player.RED ? 9 : 2;
        int palaceMinCol = 3;
        int palaceMaxCol = 5;

        // Check if the target position is within the palace
        return to.getRow() >= palaceMinRow && to.getRow() <= palaceMaxRow &&
                to.getCol() >= palaceMinCol && to.getCol() <= palaceMaxCol;
    }

    private static boolean isValidCannonMove(Board board, Position from, Position to) {
        // 直线移动
        if (from.getRow() != to.getRow() && from.getCol() != to.getCol()) {
            return false;
        }

        // 计算路径内的棋子数量
        int count = 0;

        int start = Math.min(from.getCol(), to.getCol()) + 1;
        int end = Math.max(from.getCol(), to.getCol());
        for (int col = start; col < end; col++) {
            if (board.getPieceAt(new Position(from.getRow(), col)) != null) {
                count++;
            }
        }
        start = Math.min(from.getRow(), to.getRow()) + 1;
        end = Math.max(from.getRow(), to.getRow());
        for (int row = start; row < end; row++) {
            if (board.getPieceAt(new Position(row, from.getCol())) != null) {
                count++;
            }
        }


        Piece targetPiece = board.getPieceAt(to);
        if (targetPiece == null) {//普通移动
            return count == 0;
        } else {//吃子移动
            return count == 1;
        }
    }

    private static boolean isValidSoldierMove(Position from, Position to, Player player) {
        // 每次移动一格
        int rowDiff = to.getRow() - from.getRow();
        int colDiff = Math.abs(to.getCol() - from.getCol());

        // 不能后退
        if ((player == Player.RED && rowDiff > 0) || (player == Player.BLACK && rowDiff < 0)) {
            return false;
        }
        // 只能横向或纵向移动
        if (Math.abs(rowDiff) + colDiff != 1) {
            return false;
        }

        // 过河前子只能向前
        int riverBoundary = player == Player.RED ? 5 : 4;
        return (player != Player.RED || from.getRow() < riverBoundary || colDiff == 0) &&
                (player != Player.BLACK || from.getRow() > riverBoundary || colDiff == 0);
    }

    /**
     * 目标地点的棋子是否属于同一玩家
     */
    private static boolean pieceBelongSamePlayer(Board board, Position from, Position to) {
        return board.getPieceAt(to) != null && board.getPieceAt(to).getPlayer() == board.getPieceAt(from).getPlayer();
    }


}